#ifndef TIMESPAN_H
#define TIMESPAN_H

#include <iostream>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <cstdint>

namespace libsgp4
{

namespace
{
static const int64_t TicksPerDay =  86400000000LL;
static const int64_t TicksPerHour =  3600000000LL;
static const int64_t TicksPerMinute =  60000000LL;
static const int64_t TicksPerSecond =   1000000LL;
static const int64_t TicksPerMillisecond = 1000LL;
static const int64_t TicksPerMicrosecond =    1LL;//最小为微秒

static const int64_t UnixEpoch = 62135596800000000LL;//Unix纪元（1970年1月1日00:00:00 UTC）开始时的刻度数

static const int64_t MaxValueTicks = 315537897599999999LL;//上限

// 1582-Oct-15
static const int64_t GregorianStart = 49916304000000000LL;//公历（格里高利历）开始时的刻度数
}

/**
 * @brief Represents a time interval.
 *
 * Represents a time interval (duration/elapsed) that is measured as a positive
 * or negative number of days, hours, minutes, seconds, and fractions
 * of a second.
 * 这个类（或结构体）旨在描述一个时间间隔，这个时间间隔可以是正数也可以是负数，用于表示某段时间的长度或者某个事件的持续时间。
 * 它通过天数、小时数、分钟数、秒数以及秒的小数部分来精确地表示这个时间间隔。
 * 这样的设计允许开发者在程序中处理时间差异，比如计算两个时间点之间的间隔，或者将某个时间点加上/减去一个时间间隔得到新的时间点。
 */
class TimeSpan
{
public:
    explicit TimeSpan(int64_t ticks)
        : m_ticks(ticks)
    {
    }

    TimeSpan(int hours, int minutes, int seconds)
    {
        CalculateTicks(0, hours, minutes, seconds, 0);
    }//接受时、分、秒

    TimeSpan(int days, int hours, int minutes, int seconds)
    {
        CalculateTicks(days, hours, minutes, seconds, 0);
    }//接受天、时、分、秒

    TimeSpan(int days, int hours, int minutes, int seconds, int microseconds)
    {
        CalculateTicks(days, hours, minutes, seconds, microseconds);
    }//接受天、时、分、秒、微秒

    TimeSpan Add(const TimeSpan& ts) const
    {
        return TimeSpan(m_ticks + ts.m_ticks);
    }

    TimeSpan Subtract(const TimeSpan& ts) const
    {
        return TimeSpan(m_ticks - ts.m_ticks);
    }

    int Compare(const TimeSpan& ts) const
    {
        int ret = 0;

        if (m_ticks < ts.m_ticks)
        {
            ret = -1;
        }
        if (m_ticks > ts.m_ticks)
        {
            ret = 1;
        }
        return ret;
    }//比较当前TimeSpan对象与另一个TimeSpan对象，返回0（等于）、-1（小于）或1（大于）。

    bool Equals(const TimeSpan& ts) const
    {
        return m_ticks == ts.m_ticks;
    }//判断是否相等

    int Days() const
    {
        return static_cast<int>(m_ticks / TicksPerDay);
    }

    int Hours() const
    {
        return static_cast<int>(m_ticks % TicksPerDay / TicksPerHour);
    }

    int Minutes() const
    {
        return static_cast<int>(m_ticks % TicksPerHour / TicksPerMinute);
    }

    int Seconds() const
    {
        return static_cast<int>(m_ticks % TicksPerMinute / TicksPerSecond);
    }

    int Milliseconds() const
    {
        return static_cast<int>(m_ticks % TicksPerSecond / TicksPerMillisecond);
    }

    int Microseconds() const
    {
        return static_cast<int>(m_ticks % TicksPerSecond / TicksPerMicrosecond);
    }

    int64_t Ticks() const
    {
        return m_ticks;
    }

    double TotalDays() const
    {
        return static_cast<double>(m_ticks) / TicksPerDay;
    }

    double TotalHours() const
    {
        return static_cast<double>(m_ticks) / TicksPerHour;
    }

    double TotalMinutes() const
    {
        return static_cast<double>(m_ticks) / TicksPerMinute;
    }

    double TotalSeconds() const
    {
        return static_cast<double>(m_ticks) / TicksPerSecond;
    }

    double TotalMilliseconds() const
    {
        return static_cast<double>(m_ticks) / TicksPerMillisecond;
    }

    double TotalMicroseconds() const
    {
        return static_cast<double>(m_ticks) / TicksPerMicrosecond;
    }

    std::string ToString() const
    {
        std::stringstream ss;

        ss << std::right << std::setfill('0');//右对齐，“0”填充

        if (m_ticks < 0)
        {
            ss << '-';
        }//负时间

        if (Days() != 0)
        {
            ss << std::setw(2) << std::abs(Days()) << '.';//设置接下来要输出的整数的最小宽度为2
        }

        ss << std::setw(2) << std::abs(Hours()) << ':';
        ss << std::setw(2) << std::abs(Minutes()) << ':';
        ss << std::setw(2) << std::abs(Seconds());

        if (Microseconds() != 0)
        {
            ss << '.' << std::setw(6) << std::abs(Microseconds());
        }

        return ss.str();
    }//将TimeSpan对象转换为一个表示时间的字符串，格式为[d.]hh:mm:ss[.ffffff]

private://私有，只能在类的内部被调用。
    int64_t m_ticks{};//初始化为 {}，这是C++11及以后版本的列表初始化语法，对于基本类型来说，它等同于将变量初始化为0。

    void CalculateTicks(int days,
                        int hours,
                        int minutes,
                        int seconds,
                        int microseconds)
    {
        m_ticks = days * TicksPerDay +
                  (hours * 3600LL + minutes * 60LL + seconds) * TicksPerSecond +
                  microseconds * TicksPerMicrosecond;
    }
};

inline std::ostream& operator<<(std::ostream& strm, const TimeSpan& t)
{
    return strm << t.ToString();
}

inline TimeSpan operator+(const TimeSpan& ts1, const TimeSpan& ts2)
{
    return ts1.Add(ts2);
}

inline TimeSpan operator-(const TimeSpan& ts1, const TimeSpan& ts2)
{
    return ts1.Subtract(ts2);
}

inline bool operator==(const TimeSpan& ts1, TimeSpan& ts2)
{
    return ts1.Equals(ts2);
}

inline bool operator>(const TimeSpan& ts1, const TimeSpan& ts2)
{
    return (ts1.Compare(ts2) > 0);
}

inline bool operator>=(const TimeSpan& ts1, const TimeSpan& ts2)
{
    return (ts1.Compare(ts2) >= 0);
}

inline bool operator!=(const TimeSpan& ts1, const TimeSpan& ts2)
{
    return !ts1.Equals(ts2);
}

inline bool operator<(const TimeSpan& ts1, const TimeSpan& ts2)
{
    return (ts1.Compare(ts2) < 0);
}

inline bool operator<=(const TimeSpan& ts1, const TimeSpan& ts2)
{
    return (ts1.Compare(ts2) <= 0);
}
/*定义一系列运算符
 * 运算符重载函数通常被声明为 inline，以减少函数调用的开销，并可能允许编译器在编译时进行某些优化。
 * 这些运算符重载函数使得 TimeSpan 对象可以像基本数据类型一样进行方便的输入输出和运算操作，从而提高了代码的可读性和易用性。
 */

} // namespace libsgp4

#endif // TIMESPAN_H
